//
// Created by wxd on 2025/9/17.
//

#pragma once

#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/trigonometric.hpp>
#include "../wrapper/log/Logger.h"
#include "../wrapper/monitor/GLDebug.hpp"
#include "../global/ChineseOutput.hpp"
#include "../application/app/Application.h"
#include "../glFramework/shader/Shader.h"
#include "../glFramework/texture/Texture.h"
#include "../glFramework/utils/ResourceLoadUtils.h"
#include <memory>

#include "../global/output.hpp"
#include "../application/camera/PerspectiveCamera.h"
#include "../application/camera/control/TrackBallCameraControl.h"
#include "../application/camera/control/GameFPSCameraControl.h"

#include "../glFramework/demo/light/AmbientLight.h"
#include "../glFramework/demo/light/ParallelLight.h"
#include "../glFramework/demo/material/PhongMaterial.h"
#include "../glFramework/geo/Cube.h"
#include "../glFramework/geo/Sphere.h"
#include "../glFramework/demo/mesh/Mesh.h"
#include "../glFramework/demo/renderer/Renderer.h"
#include "../glFramework/constant/engine_uniform.h"
#include "../glFramework/manager/ShaderManager.h"
#include "../glFramework/demo/light/PointLight.h"
#include "../glFramework/demo/material/LightSourceMaterial.h"
#include "../glFramework/demo/light/SpotLight.h"


struct MvpMatrix {
    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view = glm::mat4(1.0f);
    glm::mat4 proj = glm::mat4(1.0f);
};


inline const char* lightVertPath = "../assets/shader/phong/light_vertex.glsl";
inline const char* lightFragPath = "../assets/shader/phong/light_fragment.glsl";
inline const char* mainVertPath = "../assets/shader/phong/spot_light_phong_vertex.glsl";
inline const char* mainFragPath = "../assets/shader/phong/spot_light_phong_fragment.glsl";
inline const char* cubeDifTexPath = "../assets/texture/container2.png";

inline MvpMatrix mvpMatrix;

inline TrackBallCameraControl mController;
inline GameFPSCameraControl mFPSController;
inline PerspectiveCamera mCamera;

inline void onResize(int w, int h) {
    glViewport(0, 0, w, h);
}

inline void onKeyBoard(int key, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE) {
        glfwSetWindowShouldClose(EngineApp.getCurrentWindow(), true);
    }

    mFPSController.onKeyBoard(key, action, mods);
}

inline void onCursor(double xpos, double ypos) {
    mFPSController.onCursor(xpos, ypos);
}

inline void onMouse(int button, int action, int mods) {
    double x, y;
    EngineApp.getCurrentCursorPos(&x, &y);
    mFPSController.onMouse(button, action, x, y);
}

inline void render() {
    ChineseOutput::init();
    EngineApp.initWindowConfig(3, 3, GLFW_OPENGL_CORE_PROFILE,
        2560, 1800,  "FPS Camera Coontrol");
    EngineApp.setResizeCallback(onResize);
    EngineApp.setKeyBoardCallback(onKeyBoard);
    EngineApp.setCursorCallback(onCursor);
    EngineApp.setMouseCallback(onMouse);
    EngineApp.setHideMouseCursor(false);
    EngineApp.init();

    std::unique_ptr<Renderer> renderer = std::make_unique<Renderer>();

    PerspectiveParams param;
    param.fov = 45.f;
    param.aspect = EngineApp.getWindowAspectRatio();
    param.zNear = 0.1f;
    param.zFar = 100.f;
    mCamera.setPerspectiveParams(param);
    mCamera.setCameraParams(glm::vec3(0.f, 0.f, 3.f), glm::vec3(0.f, 1.f, 0.f), glm::vec3(1.f, 0.f, 0.f));
    mFPSController.setMouseCenter(EngineApp.getCurrentWindowWidth(), EngineApp.getCurrentWindowHeight());
    mFPSController.setCamera(&mCamera);
    mFPSController.setSpeed(0.005f);
    mFPSController.setSensitivity(0.03f);
    mFPSController.setPitchRange(89.0f, -89.0f);

    AmbientLight ambient = AmbientLight(
        glm::vec3(0.45f, 0.32f, 0.39f), glm::vec3(0.91f, 0.88f, 0.95f), "AmbientLight"
    );

    SpotLight spotLight = SpotLight(10.f, 15.f, glm::vec3(0.f, 0.f, -1.f));
    spotLight.setPos(glm::vec3(0.f, 0.f, -4.f));


    // 着色器
    Shader* lightShader = new Shader(lightVertPath, lightFragPath);
    Shader* mainShader = new Shader(mainVertPath, mainFragPath);

    // 纹理
    std::unique_ptr<Texture> modelDifTexture = std::make_unique<Texture>(cubeDifTexPath, 0);

    // mesh队列
    std::vector<std::reference_wrapper<Mesh>> meshQueue;
    meshQueue.reserve(2);

    // model材质
    std::unique_ptr<PhongMaterial> modelMaterial = std::make_unique<PhongMaterial>("ModelPhongMaterial");
    modelMaterial->setShininess(256.f);
    modelMaterial->setDiffuseTexture(std::move(modelDifTexture));

    // 注册材质和着色器 note：std::move转移独占指针的所有权之后，当前独占指针为空，所以必须在std::move(modelMaterial)之前进行注册，否则有空指针问题
    ShaderManager::getInstance().addShader(modelMaterial->getTraceId(), mainShader);

    // model几何数据
    std::unique_ptr<Cube> geo = std::make_unique<Cube>(4.0f, glm::vec3(0.f, 0.f, -10.f));

    // model的mesh
    Mesh* modelMesh = new Mesh("ModelMesh");
    modelMesh->setMaterial(std::move(modelMaterial));
    modelMesh->setGeometry(std::move(geo));

    meshQueue.push_back(*modelMesh);

    // 光源
    std::unique_ptr<LightSourceMaterial> lightMaterial = std::make_unique<LightSourceMaterial>("LightSourceMaterial");
    // 注册光源材质着色器
    ShaderManager::getInstance().addShader(lightMaterial->getTraceId(), lightShader);
    // 光源几何数据
    std::unique_ptr<Sphere> lightModel = std::make_unique<Sphere>(0.04f, glm::vec3(0.f, 0.f, -1.5f), glm::vec3(1.f));
    // 光源Mesh
    Mesh* lightMesh = new Mesh("LightMesh");
    lightMesh->setMaterial(std::move(lightMaterial));
    lightMesh->setGeometry(std::move(lightModel));
    meshQueue.push_back(*lightMesh);

    while (EngineApp.update()) {
        mFPSController.update();
        float z = -3.5 + 3.5 * glm::sin(glm::radians(100.f * glfwGetTime()));
        lightMesh->setPosZ(z);
        spotLight.setPos(lightMesh->getPosition());
        renderer->render_V4(mCamera, meshQueue, ambient, spotLight);
    }

    meshQueue.clear();
    delete lightShader;
    delete mainShader;
    delete modelMesh;
    delete lightMesh;
}